﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using LEDX.Components.ColorPicker.ExtensionMethods;

namespace LEDX.Components.ColorPicker.ColorModels.RGB {
	/// <summary>
	/// Interaction logic for RgbDisplay.xaml
	/// </summary>
	public partial class RgbDisplay : UserControl {
		public enum EDisplayMode {
			ByteDisplay,
			PercentNoDecimal
		}

		private bool processEvents = true;

		private Func<Color, string> r;
		private Func<Color, string> g;
		private Func<Color, string> b;

		private Func<Color, byte, Color> setR;
		private Func<Color, byte, Color> setG;
		private Func<Color, byte, Color> setB;

		public static Type ClassType {
			get { return typeof(RgbDisplay); }
		}
		public RgbDisplay() {
			InitializeComponent();
			r = c => c.R.ToString();
			g = c => c.G.ToString();
			b = c => c.B.ToString();

			setR = (c, newR) => c.WithR(newR);
			setG = (c, newG) => c.WithG(newG);
			setB = (c, newB) => c.WithB(newB);
		}

		private static Red sRed = new Red();
		private static Green sGreen = new Green();
		private static Blue sBlue = new Blue();

		public event EventHandler<EventArgs<Color>> ColorChanged;

		public event EventHandler<EventArgs<NormalComponent>> ColorComponentChanged;


		#region DisplayMode

		public static DependencyProperty DisplayModeProperty = DependencyProperty.Register("DisplayMode", typeof(EDisplayMode), ClassType, new PropertyMetadata(EDisplayMode.ByteDisplay, OnDisplayModeChanged));

		[Category("ColorPicker")]
		public EDisplayMode DisplayMode {
			get {
				return (EDisplayMode)GetValue(DisplayModeProperty);
			}
			set {
				SetValue(DisplayModeProperty, value);
			}
		}

		private static void OnDisplayModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			var display = (RgbDisplay)d;
			var displayMode = (EDisplayMode)e.NewValue;
			display.OnDisplayModeChanged(displayMode);

		}

		private void OnDisplayModeChanged(EDisplayMode displayMode) {
			switch (displayMode) {
				case EDisplayMode.ByteDisplay:
					txtRUnit.Text = "";
					txtGUnit.Text = "";
					txtBUnit.Text = "";

					r = c => c.R.ToString();
					g = c => c.G.ToString();
					b = c => c.B.ToString();

					setR = (c, newR) => c.WithR(newR);
					setG = (c, newG) => c.WithG(newG);
					setB = (c, newB) => c.WithB(newB);

					break;
				case EDisplayMode.PercentNoDecimal:
					txtRUnit.Text = "%";
					txtGUnit.Text = "%";
					txtBUnit.Text = "%";

					r = c => c.R.AsPercent().ToString();
					g = c => c.G.AsPercent().ToString();
					b = c => c.B.AsPercent().ToString();

					setR = (c, newR) => c.WithR(FromPercent(newR));
					setG = (c, newG) => c.WithG(FromPercent(newG));
					setB = (c, newB) => c.WithB(FromPercent(newB));
					break;

			}
			processEvents = false;
			txtR.Text = r(Color);
			txtG.Text = g(Color);
			txtB.Text = b(Color);
			processEvents = true;
		}

		#endregion

		#region Color

		public static DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Color), ClassType,
				 new FrameworkPropertyMetadata(Colors.Black, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnColorChanged));

		[Category("ColorPicker")]
		public Color Color {
			get {
				return (Color)GetValue(ColorProperty);
			}
			set {
				SetValue(ColorProperty, value);
			}
		}

		private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			var c = (Color)e.NewValue;
			var rd = (RgbDisplay)d;
			rd.OnColorChanged(c);
		}

		private void OnColorChanged(Color c) {

			processEvents = false;
			txtR.Text = r(c);
			txtG.Text = g(c);
			txtB.Text = b(c);
			processEvents = true;
			if (ColorChanged != null) {
				ColorChanged(this, new EventArgs<Color>(c));
			}
		}

		#endregion


		#region NormalComponent

		public static DependencyProperty NormalComponentProperty = DependencyProperty.Register("NormalComponent", typeof(NormalComponent), ClassType,
				new FrameworkPropertyMetadata(sRed, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnColorComponentChanged));

		[Category("ColorPicker")]
		public NormalComponent NormalComponent {
			get {
				return (NormalComponent)GetValue(NormalComponentProperty);
			}
			set {
				SetValue(NormalComponentProperty, value);
			}
		}

		private static void OnColorComponentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			try {
				var cp = (NormalComponent)e.NewValue;
				var rd = (RgbDisplay)d;
				rd.OnColorComponentChanged(cp);
			} catch {
			}
		}

		#endregion

		private void OnColorComponentChanged(NormalComponent colorPlaneColorComponent) {

			if (colorPlaneColorComponent.Name == "RGB_Red") {
				rR.IsChecked = true;
			} else if (colorPlaneColorComponent.Name == "RGB_Green") {
				rG.IsChecked = true;
			} else if (colorPlaneColorComponent.Name == "RGB_Blue") {
				rB.IsChecked = true;
			} else {
				rR.IsChecked = false;
				rG.IsChecked = false;
				rB.IsChecked = false;
			}

			if (ColorComponentChanged != null) {
				ColorComponentChanged(this, new EventArgs<NormalComponent>(colorPlaneColorComponent));
			}
		}

		private void rR_Checked(object sender, RoutedEventArgs e) {
			NormalComponent = sRed;
			if (ColorComponentChanged != null) {
				ColorComponentChanged(this, new EventArgs<NormalComponent>(sRed));
			}
		}

		private void rG_Checked(object sender, RoutedEventArgs e) {
			NormalComponent = sGreen;
			if (ColorComponentChanged != null) {
				ColorComponentChanged(this, new EventArgs<NormalComponent>(sGreen));
			}
		}

		private void rB_Checked(object sender, RoutedEventArgs e) {
			NormalComponent = sBlue;
			if (ColorComponentChanged != null) {
				ColorComponentChanged(this, new EventArgs<NormalComponent>(sBlue));
			}
		}

		private void TextChanged(object sender, TextChangedEventArgs e) {
			try {
				if (processEvents) {
					if (sender == txtR) {
						Color = setR(Color, byte.Parse(txtR.Text));
					} else if (sender == txtG) {
						Color = setG(Color, byte.Parse(txtG.Text));
					} else if (sender == txtB) {
						Color = setB(Color, byte.Parse(txtB.Text));
					}
					//Color = System.Windows.Media.Color.FromRgb(byte.Parse(txtR.Text), byte.Parse(txtG.Text),
					//                                           byte.Parse(txtB.Text));
				}
			} catch (Exception ex) {
				Debug.WriteLine(ex.Message);
			}
		}

		private void txtR_PreviewTextInput(object sender, TextCompositionEventArgs e) {
			if (processEvents) {
				e.Handled = NumbersOnly(e.Text);
				base.OnPreviewTextInput(e);
			}
		}

		private bool NumbersOnly(string text) {
			String okChars = "0123456789";
			return text.ToCharArray().All(c => okChars.IndexOf(c) == -1);
		}

		public static byte FromPercent(int percent) {
			return Convert.ToByte((double)percent / 100 * 255);
		}


	}
}
